package com.system.handler;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.alibaba.fastjson.JSON;
import com.system.base.ApiResult;

import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * 全局异常处理器,处理新增的异常，对于有特殊逻辑的返回直接定义个新方法，参考ServiceException
 * 
 * @Package: com.steel.base
 * @ClassName: GlobalExceptionHandler.java
 * @Description:全局异常处理器
 * 
 * @author kaifa008
 * @date 2022年3月24日 下午1:55:51
 * @Copyright: 2022 Copyright (c) 2018 LgSteel
 */
@SuppressWarnings("rawtypes")
@ControllerAdvice
@Slf4j
@Component
public class GlobalExceptionHandler {

	private static final String ERROR_PATH = "error/error";
	
	/**
	 * 返回json数据处理异常
	 * @param exception
	 * @return
	 */
	@ExceptionHandler(value = ServiceException.class)
	@ResponseBody
	public ApiResult allExpection(ServiceException exception) {
		// log.error("日志错误信息：", exception);
		return ApiResult.build(exception.getCode(), exception.getMessage());
	}

	/**
	 * 断言处理啊，根据请求返回数据或页面，自定义message
	 * @param request
	 * @param response
	 * @param e
	 * @return
	 * @throws Exception
	 */
	@ExceptionHandler(value = IllegalArgumentException.class)
	public Object allExpection(HttpServletRequest request, HttpServletResponse response, IllegalArgumentException e) throws Exception {
		if (isAjax(request)) {
			response.setContentType("application/json; charset=UTF-8");
			String message = StringUtils.isNotEmpty(e.getMessage()) ? e.getMessage() : "请联系管理员！";
			response.getWriter().write(JSON.toJSONString(ApiResult.build(400, message)));
			response.getWriter().close();
			return null;
		}
		// 返回错误页面
		ModelAndView mav = new ModelAndView();
		mav.addObject("exception", e);
		mav.addObject("message", e.getMessage());
		mav.addObject("url", request.getRequestURL());
		mav.setViewName(ERROR_PATH);
		return mav;
	}
	
	/**
	 * 未知异常，统一邮件提醒
	 * @param request
	 * @param response
	 * @param e
	 * @return
	 * @throws Exception
	 */
	@ExceptionHandler(value = Exception.class)
	public Object errorHandler(HttpServletRequest request, HttpServletResponse response, Exception e) throws Exception {
		// 未知异常，则发送邮件提醒
		try {
			// 判断某些方法不作处理
			log.error("日志错误信息：", e);
			createMailMQForSend(request, e);
		} catch (Exception taskExecutorException) {
			taskExecutorException.printStackTrace();
		}
		if (isAjax(request)) {
			response.setContentType("application/json; charset=UTF-8");
			response.getWriter().write(JSON.toJSONString(ApiResult.build(500, "请联系管理员！")));
			response.getWriter().close();
			return null;
		}
		// 返回错误页面
		ModelAndView mav = new ModelAndView();
		mav.addObject("exception", e);
		mav.addObject("url", request.getRequestURL());
		mav.setViewName(ERROR_PATH);
		return mav;
	}

	/**
	 * @description 判断是否是ajax请求
	 * @return boolean
	 */
	public static boolean isAjax(HttpServletRequest httpRequest) {
		return (httpRequest.getHeader("X-Requested-With") != null
				&& "XMLHttpRequest".equals(httpRequest.getHeader("X-Requested-With").toString()));
	}
	
	private void createMailMQForSend(HttpServletRequest request, Exception exception) {
		try {
			String exceptionOut = ExceptionUtils.getFullStackTrace(exception);
			String userAgent = request.getHeader("User-Agent");
			if (StringUtils.isEmpty(userAgent)) {
				userAgent = "";
			} else {
				// 暂定50字
				userAgent = userAgent.toLowerCase();
				if (userAgent.length() > 50) {
					userAgent = userAgent.substring(0, 50);
				}
			}
			Map<String, Object> mqMap = new HashMap<>();
			mqMap.put("userAgent", userAgent);
			mqMap.put("uri", request.getRequestURI());
			mqMap.put("url", request.getRequestURL().toString());
			mqMap.put("method", request.getMethod());
			mqMap.put("systemType", "0");
			mqMap.put("description", "测试系统");
			mqMap.put("exceptionDetails", exceptionOut);
			asynCreateMailMQForSend(mqMap);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public void asynCreateMailMQForSend(Map<String, Object> requestMap) throws Exception {
		log.error("发送MQ信息：{}", JSONUtil.parse(requestMap).toString());
	}
	
}
